﻿using HeinQi.Framework.LayerBases;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TbShop.Entity;

namespace TbShop.Data.Components
{
    public class DataComponentsBase<TEntityBase> : IDataComponentsBase<TEntityBase> where TEntityBase : DataEntityBase
    {
        //public CIRevolutionDbContext DBContext
        //{
        //    get
        //    {
        //        return CIRevolutionDbContext.GetInstance();
        //    }
        //}
        public TbShopDBContext DBContext = new TbShopDBContext();

        public TEntityBase Get(int id)
        {
            return DBContext.GetSets<TEntityBase>().SingleOrDefault(c => c.Id == id);
        }

        /// <summary>
        /// 物理删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Delete(int id)
        {
            var entity = Get(id);
            DBContext.GetSets<TEntityBase>().Remove(entity);
            return this.SaveChanges() > 0;
        }

        /// <summary>
        /// 物理删除
        /// </summary>
        /// <param name="id"></param>
        /// <param name="versionNumber"></param>
        /// <returns></returns>
        public bool Delete(int id, int versionNumber)
        {
            var item = this.Get(id);
            if (versionNumber == item.VersionNumber)
            {
                return this.Delete(item);
            }
            else
            {
                throw new CustomerException.VersioNumberException();
            }
        }


        /// <summary>
        /// 物理删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Delete(TEntityBase entity)
        {
            DBContext.GetSets<TEntityBase>().Remove(entity);
            return this.SaveChanges() > 0;
        }
        public TEntityBase Remove(TEntityBase item)
        {
            item.IsDeleted = true;
            return this.Save(item);
        }

        public TEntityBase Remove(int id, int versionNumber)
        {
            var item = this.Get(id);
            if (versionNumber == item.VersionNumber)
            {
                return this.Remove(item);
            }
            else
            {
                throw new CustomerException.VersioNumberException();
            }
        }

        public void RemoveAll(IEnumerable<TEntityBase> items)
        {
            if (items != null)
            {
                foreach (var item in items)
                {
                    item.IsDeleted = true;
                }
                this.SaveChanges();
            }
        }

        public void RemoveAll(IEnumerable<int> items)
        {
            if (items != null)
            {
                foreach (var item in items)
                {
                    var data = Get(item);
                    if (data != null)
                    {
                        data.IsDeleted = true;
                    }
                }
                this.SaveChanges();
            }
        }

        public TEntityBase Update(TEntityBase item)
        {
            if (DBContext.Entry(item).State == System.Data.Entity.EntityState.Detached)
            {
                TEntityBase originalItem = DBContext.Set<TEntityBase>().Find(item.Id);
                if (originalItem == null)
                {
                    DBContext.Set(item.GetType()).Attach(item);
                    DBContext.Entry(item).State = System.Data.Entity.EntityState.Modified;
                }
                else
                {
                    var createdBy = originalItem.CreatedBy;
                    var createdOn = originalItem.CreatedDate;
                    DBContext.Entry(originalItem).CurrentValues.SetValues(item);
                    originalItem.CreatedBy = createdBy;
                    originalItem.CreatedDate = createdOn;
                }
            }
            else if (DBContext.Entry(item).State != System.Data.Entity.EntityState.Modified)
            {
                DBContext.Set(item.GetType()).Attach(item);
                DBContext.Entry(item).State = System.Data.Entity.EntityState.Modified;
            }
            return this.SaveChanges() > 0 ? item : null;
        }

        public void Update(TEntityBase item, bool isSaveChange)
        {
            if (DBContext.Entry(item).State == System.Data.Entity.EntityState.Detached)
            {
                TEntityBase originalItem = DBContext.Set<TEntityBase>().Find(item.Id);
                if (originalItem == null)
                {
                    DBContext.Set(item.GetType()).Attach(item);
                    DBContext.Entry(item).State = System.Data.Entity.EntityState.Modified;
                }
                else
                {
                    var createdBy = originalItem.CreatedBy;
                    var createdOn = originalItem.CreatedDate;
                    DBContext.Entry(originalItem).CurrentValues.SetValues(item);
                    originalItem.CreatedBy = createdBy;
                    originalItem.CreatedDate = createdOn;
                }
            }
            else if (DBContext.Entry(item).State != System.Data.Entity.EntityState.Modified)
            {
                DBContext.Set(item.GetType()).Attach(item);
                DBContext.Entry(item).State = System.Data.Entity.EntityState.Modified;
            }
            if (isSaveChange)
            {
                this.SaveChanges();
            }
        }

        public TEntityBase Add(TEntityBase item)
        {
            var res = DBContext.GetSets<TEntityBase>().Add(item);
            return this.SaveChanges() > 0 ? res : null;
        }

        public TEntityBase Add(TEntityBase item, bool isSaveChange)
        {
            var res = DBContext.GetSets<TEntityBase>().Add(item);
            if (isSaveChange)
            {
                return this.SaveChanges() > 0 ? res : null;
            }
            return res;
        }


        public IQueryable<TEntityBase> GetAllWithDeleted()
        {
            return DBContext.GetSets<TEntityBase>().OrderByDescending(p => p.CreatedDate);
        }

        public IQueryable<TEntityBase> GetAllWithDeleted(int pageIndex, int pageSize, out int count)
        {
            count = GetAllWithDeleted().Count();
            return GetAllWithDeleted().OrderByDescending(p => p.CreatedDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public IQueryable<TEntityBase> GetAll()
        {
            return DBContext.GetSets<TEntityBase>().Where(p => !p.IsDeleted).OrderByDescending(p => p.CreatedDate);
        }

        public IEnumerable<TEntityBase> GetAll(IOrderedQueryable<TEntityBase> models, int pageIndex, int pageSize, out int count)
        {
            count = models.Count();
            return models.Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public IEnumerable<TEntityBase> GetAll(IQueryable<TEntityBase> models, int pageIndex, int pageSize, out int count)
        {
            count = models.Count();
            return models.OrderByDescending(p => p.CreatedDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public IEnumerable<TEntityBase> GetAll(int pageIndex, int pageSize, out int count)
        {
            count = GetAll().Count();
            return GetAll().OrderByDescending(p => p.CreatedDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public TEntityBase Save(TEntityBase item)
        {
            if (item.Id != 0)
            {
                return Update(item);
            }
            else
            {
                return Add(item);
            }
        }

        public IEnumerable<TEntityBase> SaveRange(IEnumerable<TEntityBase> list)
        {
            var returnDataList = new List<TEntityBase>();
            TEntityBase returnData;
            foreach (var item in list)
            {
                returnData = this.Save(item);
                returnDataList.Add(returnData);
            }
            return returnDataList.AsQueryable();
        }

        public IEnumerable<TEntityBase> AddRange(IEnumerable<TEntityBase> list)
        {
            if (list == null)
                return null;
            var returnDataList = new List<TEntityBase>();
            TEntityBase returnData;
            foreach (var item in list)
            {
                if (GetAll().Any(p => p.Id == item.Id))
                {
                    Remove(Get(item.Id));
                }
                returnData = this.Add(item);
                returnDataList.Add(returnData);
            }
            return returnDataList.AsQueryable();
        }

        public void UpdateRange(IEnumerable<TEntityBase> list)
        {
            foreach (var item in list)
            {
                if (DBContext.GetSets<TEntityBase>().Any(p => p.Id == item.Id))
                {
                    this.Update(item);
                }
                else
                {
                    this.Add(item);
                }
            }
        }

        public int SaveChanges()
        {
            return DBContext.SaveChanges();
        }

        public void Dispose()
        {
            DBContext.Dispose();
        }
    }
}
